{-# OPTIONS_GHC -fglasgow-exts -XTemplateHaskell -XNoMonomorphismRestriction#-}
module Main where
import Text.XML.Xmlable
import Text.HTML.TagSoup
import Control.Monad
import Test.HUnit
import Prelude hiding (readFile, writeFile, log, putStrLn, getLine)
import System.IO.UTF8 (readFile, writeFile, putStrLn, getLine, hPutStr)
import System.IO hiding (readFile, writeFile, putStrLn, getLine, hPutStr)
import Data.Monoid(mempty)
import qualified Rename
import qualified Data.Map as Map

mkXmlableFieldsCount 3

data X2 = X2 {f21 :: Int, f22 :: Maybe String} |
        X22 (Maybe Float) Int |
        X23 {f231 :: Float, f232 :: Int, f233 :: String} |
        X24 {f241 :: Float, f242 :: Int, f243 :: Integer} |
        X25 (Maybe Float) Int
        deriving (Eq, Show)
data X3 = X3 {f31 :: Int, f32 :: [X2], f33 :: Int} |
        X32 { n1 :: Maybe String, n2 :: X2} deriving (Eq, Show)
data X4 = X41 X3 X2 | X42 Int (Maybe String) | X43 { f431 :: String, f432 :: String, f433 :: Bool } deriving (Eq, Show)

deriveXmlables False Rename.f [''X2, ''X3, ''X4]

type TstX a = Maybe (a, [Xml])

testXml :: Test
testXml = "testXml" ~:
--    concat $ replicate 100
    [
        "test Simple" ~: [
            run' parse (Nothing, []) [Val "5", Attr "x" "10"] @?= Right (5 :: Int)
            , run' parse (Nothing, []) [Val "5", Attr "x" "10"] @?= Right (5 :: Integer)
            , run'' parseSafe (Nothing, []) [] @?= (Left $ Errors [(-1, "There is not enough xml data")] :: Either Errors Int)
            , eitherParse parseSafe (Nothing, []) [Attr "z" "test", Attr "x" "10"] @?= (Right (Nothing :: Maybe Int), [Attr "z" "test", Attr "x" "10"])
            , eitherParse parseSafe (Nothing, []) [Val "test", Attr "x" "10"] @?= (Right (Nothing :: Maybe Int), [Val "test", Attr "x" "10"])
            , eitherParse parse (Nothing, []) [Val "test", Attr "x" "10"] @?= (Right "test", [Attr "x" "10"])
            , eitherParse parse (Nothing, []) [Val "", Attr "x" "10"] @?= (Right "", [Attr "x" "10"])
            , eitherParse parse (Just $ XdcAttr "a", [])  [Attr "a" "test", Attr "x" "10"] @?= (Right "test", [Attr "x" "10"])
            , eitherParse parse (Just $ XdcElem "a" [], [])  [ElemB "a" mempty, Val "test", ElemE, Attr "x" "10"] @?= (Right "test", [Attr "x" "10"])
            , run' parse        (Just $ XdcElem "a" [], [])  [ElemB "a" mempty, Val "test", ElemE] @?= Right "test"
            , eitherParse parse (Just $ XdcAttr "a", [])  [Attr "a" "t", Attr "x" "10"] @?= (Right 't', [Attr "x" "10"])
            , eitherParse parse (Just $ XdcAttr "a", [])  [Attr "a" "test", Attr "x" "10"] @?= (Right 't', [Attr "a" "est", Attr "x" "10"])
        ]
        , "test Elems" ~: [
            run' parse (Nothing, []) [ElemB "X2" mempty, Attr "f22" "str", Attr "f21" " 5 ", ElemE] @?= (Right $ X2 5 (Just "str"))
            , run' parse (Nothing, []) [ElemB "X25" mempty, Val " 5 ", ElemE] @?= (Right $ X25 Nothing 5)
            , run' parse (Nothing, []) [ElemB "X2" mempty, Attr "f21" " 5 ", Attr "f22" "str", ElemE] @?= (Right $ X2 5 (Just "str"))
            , run' parse (Nothing, []) [ElemB "X2" mempty, Attr "f21" " 5 ", ElemE] @?= (Right $ X2 5 Nothing)
            , run' parse (Nothing, []) [ElemB "X2" mempty, Attr "f22" " str ", Attr "f21" " 5 ", ElemE] @?= (Right $ X2 5 (Just " str "))
            , run' parse (Nothing, []) [ElemB "X32" mempty, Attr "n1" " str ", ElemB "n2" mempty, Val " 5 ", ElemE, ElemE] @?= (Right $ X32 (Just " str ") (X25 Nothing 5))
            , run' parse (Nothing, []) [ElemB "X32" mempty, ElemB "n2" mempty, Attr "f21" " 5 ", Attr "f22" "str", ElemE, Attr "n1" " str ", ElemE] @?= (Right $ X32 (Just " str ") (X2 5 (Just "str")))
            , eitherParse parse (Nothing, []) [ElemB "X2" mempty, Attr "f21" " 5 ", Attr "f22" "Тест!", ElemE, ElemB "X2" mempty, Val " null ", Val "3", ElemE, Attr "x" "10"] @?=
                    (Right $ X2 5 (Just "Тест!"), [ElemB "X2" mempty, Val " null ", Val "3", ElemE, Attr "x" "10"])
        ]
        , "test Lists" ~: [
            eitherParse parse (Nothing, []) [Val "  5  15.1  79 ", Attr "x" "10"] @?= (Right [5 :: Float, 15.1, 79], [Attr "x" "10"])
            , run' parse (Nothing, []) [ElemB "X2" mempty, Attr "f21" " 5 ", Attr "f22" "str", ElemE, ElemB "X2" mempty, Attr "f22" " null ", Attr "f21" " 3 ", ElemE] @?=
                    Right [X2 5 (Just "str"), X2 3 (Just " null ")]
            , eitherParse parse (Nothing, []) [ElemB "X2" mempty, Attr "f21" " 5 ", Attr "f22" "str", ElemE, ElemB "X2" mempty,  Attr "f22" " null ", Attr "f21" " 3 ", ElemE, Attr "x" "10"] @?=
                    (Right [X2 5 (Just "str"), X2 3 (Just " null ")], [Attr "x" "10"])
            , 
            eitherParse parseSafe (Nothing, []) [Attr "x" "10"] @?= (Right ([]::[X2]), [Attr "x" "10"])
            , eitherParse parseSafe (Nothing, []) [Attr "f232" "10"] @?= (Right ([]::[X2]), [Attr "f232" "10"])
            , run' parseSafe (Nothing, []) [Attr "x" "10 20"] @?= Right ([10,20]::[Int])
            , run'' parse (Nothing, []) [ElemB "X3" mempty,
                            ElemB "f32" mempty, Attr "f232" "4", {- Attr "f232" "4", -} ElemE,
                            ElemB "f32" mempty, Attr "f232" "41", Attr "f231" "3.5", ElemE,
                            Attr "f33" " 5 ",
                            Attr "f31" "10",
                            ElemE
                    ] @?= (Right $ X3 10 [
                                    X22 Nothing 4,
                                    X22 (Just 3.5) 41
                                ] 5)
            , run'' parse (Nothing, []) [
                            ElemB "X3" mempty
                                , Attr "f33" " 5 "
                                , ElemB "f32" mempty, Attr "f232" "4", ElemE
                                , ElemB "f32" mempty, Attr "f232" "4", ElemE
                                , ElemB "f32" mempty, Attr "f21" "15", Attr "f22" "test22", ElemE
--                             ElemB "f32" mempty, Attr "f21" "test22", Attr "f22" "10", ElemE
                                , Attr "f31" "10"
                            , ElemE] @?= (Right $ X3 10 [X22 Nothing 4, X22 Nothing 4, X2 15 $ Just "test22"] 5)
            , eitherParse parse (Nothing, []) [ElemB "X22" mempty, Attr "f232" "4", ElemE
                            , ElemB "X2" mempty, Attr "f22" "test22", Attr "f21" "15", ElemE
                            , ElemB "X2" mempty, Attr "f22" "test22", Attr "f21" "10", ElemE
                ] @?= (Right [X22 Nothing 4], -- неименованные списки должны содержать элементы с одним именем
                    [ElemB "X2" mempty, Attr "f22" "test22", Attr "f21" "15", ElemE, ElemB "X2" mempty, Attr "f22" "test22", Attr "f21" "10", ElemE])
        ]
        , "test names" ~: [
            run' parse (Nothing, []) [ElemB "X23" mempty, Attr "f231" "4.0", Attr "f232" "7", Attr "f233" "qwe", ElemE] @?= Right (X23 4 7 "qwe")
            , run' parse (Nothing, []) [ElemB "X24" mempty, Attr "f241" "4.0", Attr "f242" "7", Attr "f243" "5", ElemE] @?= Right (X24 4 7 5)
            , run' parse (Nothing, []) [ElemB "X23" mempty, Attr "f233" "qwe", Attr "f232" "7", Attr "f231" "4.0", ElemE] @?= Right (X23 4 7 "qwe")
            , run' parse (Nothing, []) [ElemB "X24" mempty, Attr "f243" "4", Attr "f242" "7", Attr "f241" "5", ElemE] @?= Right (X24 5 7 4)
        ]
        , "test X4" ~: [
            run' parse (Nothing, []) [ElemB "X42" mempty, Attr "str" "val", Attr "num" "23", ElemE] @?= Right (X42 23 (Just "val"))
            -- ,  run' parse (Nothing, []) [ElemB "X41" mempty, Attr "v1" "str", Attr "v2" "23", ElemE] @?= (Right $ X42 23 (Just "str"))
            , run' parse (Nothing, []) [ElemB "ns1:X41" $ Map.fromList [("ns1", "http://haskell.org/Main")], ElemB "ns0:X32" mempty, 
                ElemB "n2" mempty, Attr "f21" " 5 ", Attr "f22" "str", ElemE, Attr "n1" " str ", ElemE,
                ElemB "X2" mempty, Attr "f22" " str ", Attr "f21" " 5 ", ElemE, ElemE] @?=
                    Right (X41 (X32 (Just " str ") $ X2 5 $ Just "str") $ X2 5 $ Just " str ")
        ]
        , "testTuples" ~: [
            run' parse (Nothing, []) [Val "5", ElemB "X32" mempty, ElemB "n2" mempty, Val " 12 ", ElemE, ElemE] @?= Right (5 :: Int, X32 Nothing (X25 Nothing 12))
            , run''' parse (Nothing, []) [Val "5", ElemB "X32" mempty, ElemB "n2" mempty, Val " 12 ", ElemE, ElemE] @?= (Left mempty :: Either Errors (X3, Int))
        ]
        , "testToXml" ~: [
            toXml Nothing (5::Integer) @?= [Val "5"]
            , toXml (Just $ XtElem "test") (5.1::Float) @?= [ElemB "test" mempty, Val "5.1", ElemE]
            , toXml (Just $ XtAttr "test") (5.1::Double) @?= [Attr "test" "5.1"]
            , toXml Nothing [1..3::Int] @?= [Val "1 2 3"]
            , run' parse (Nothing, []) (toXml Nothing [1..3::Int]) @?= Right [1..3::Int]
            , run' parse (Nothing, []) (toXml Nothing $ Just "str") @?= Right (Just "str")
            , run' parse (Just $ XdcElem "a" [], []) (toXml (Just $ XtElem "a") $ Just "str") @?= Right (Just "str")

            , tst (X42 23 $ Just "val")
            -- , tst [X22 Nothing 4]   -- error!
            , tst (Just "str")
        ]]
    where
        noX3 = Nothing :: TstX X3
        tstId = run' parse (Nothing, []) . toXml Nothing
        tst a = tstId a @?= Right a

data Customers = Customers {custs :: [Customer] } deriving (Eq, Show)
data Customer = Customer { name :: String, orders :: [Order] } deriving (Eq, Show)
data Order = Order { {- date :: Maybe String, -} num :: String, positions :: [OrdPos] } deriving (Eq, Show)
data OrdPos = OrdPos { material :: String, price :: Double, quantity :: Int } deriving (Eq, Show)
deriveXmlables False id [''OrdPos, ''Order, ''Customer, ''Customers]

genData :: Customers
genData = Customers [
        Customer { name = "name" ++ show i, orders = [
                Order { {- date = Nothing, -} num = "num" ++ show j, positions = [
                        OrdPos { material = "mat" ++ show k, price = fromIntegral k * 10.5, quantity = mod k 10} |
                        k <- [1..20] :: [Int]
                    ] } |
                j <- [1..50]
            ] } |
            i <- [1..10]
        ]

main :: IO ()
main = runTestTT testXml >>
    putStrLn ""
--    >> writeFile "genData" (renderTags $ toTS $ toXml Nothing genData)
--    >> readFile "genData" >>= writeFile "genData6" . either show (const "success" {- unlines . map show . custs -} ) . run'' (parse :: ParserXml Customers) Nothing . fromTS . parseTags

{-
    >> mapM_ putStrLn (lines $ show $ run (parse::ParserXml X3) (Just (XmlDesc XtElem "X3", [])) [
            ElemB "X3"
                , Attr "f33" " 5 "
                , ElemB "f32"
                    , Attr "f232" "4"
                , ElemE
                , ElemB "f32"
                    , Attr "f22" "test22"
                    , Attr "f21" "15"
                , ElemE
                , ElemB "f32"
                    , Attr "f22" "test22"
                    , Attr "f21" "10"
                , ElemE
                , Attr "f31" "10"
            , ElemE
        ])
-}
--    >> mapM_ (appendFile "run.res") (lines $ showErr $ run' (parseSafe :: ParserXml Int) Nothing [])
--    >> readFile "price1.xml" >>= return . fromTS . parseTags >>= \xs -> writeFile "fromTs" (show xs)
--    >> (writeFile "res" $ show $ run (parse::ParserXml DT_Price) (XmlDesc XtElem "MT_Price") xs)

